/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.andersen.web.service;

import com.andersen.database.dao.ComponentTypeDao;
import com.andersen.database.entity.ComponentTypeEntity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;

/**
 *
 * @author Corvus 11
 */
public class ComponentTypeTree {
    
    private static final String JSON_ATTRIBUTE_TYPE_NAME = "typeName";
    private static final String JSON_ATTRIBUTE_TYPE_ID = "typeId";
    private static final String JSON_ATTRIBUTE_SUBTYPES = "typeSubtypes";
    
    private static final Logger LOG = Logger.getLogger(ComponentTypeTree.class);
    
    private static ComponentTypeTree instance = null;
    
    private ArrayList<ComponentTypeEntity> mainTypes = null;
    private TreeMap<Long,ComponentTypeEntity> navigationTree = null;

    private ComponentTypeTree() {}
    
    public static ComponentTypeTree getTree(ComponentTypeDao dao) {
        if (instance == null) {
            HashMap<Long,ArrayList<ComponentTypeEntity>> map = dao.getAllComponentsTypes();
            instance = new ComponentTypeTree();
            instance.loadTree(map);
        }
        return instance;
    }

    public ArrayList<ComponentTypeEntity> getMainTypes() {
        return mainTypes;
    }
    
    private void loadTree(HashMap<Long,ArrayList<ComponentTypeEntity>> treeMap) {
        
        mainTypes = new ArrayList<ComponentTypeEntity>(treeMap.get(0l));
        navigationTree = new TreeMap<Long, ComponentTypeEntity>();
        
        for(ComponentTypeEntity mt : mainTypes) {
            loadChildren(mt, treeMap);
            navigationTree.put(mt.getId(), mt);
        }
    }

    private void loadChildren(ComponentTypeEntity mt, HashMap<Long,ArrayList<ComponentTypeEntity>> treeMap) {
        
        if (!treeMap.containsKey(mt.getId())) return;
        ArrayList<ComponentTypeEntity> children = new ArrayList<ComponentTypeEntity>(treeMap.get(mt.getId()));
        
        if (children.size() > 0) {
            mt.setChildTypes(children);
            for(ComponentTypeEntity child : children) {
                LOG.info("adding " + child + " to " + mt);
                child.setParentType(mt);
                child.setParentTypeId(mt.getId());
                loadChildren(child, treeMap);
                navigationTree.put(child.getId(), child);
            }
        }
    }
    
    public void dispose() {
        if (mainTypes == null) return;
        for(ComponentTypeEntity mt : mainTypes) {
            freeChildren(mt);
        }
        mainTypes.clear();
        mainTypes = null;
        navigationTree.clear();
        navigationTree = null;
    }
    
    private void freeChildren(ComponentTypeEntity node) {
        if (node.getChildTypes() != null) {
            for(ComponentTypeEntity nt : node.getChildTypes()) {
                freeChildren(nt);
            }
            node.getChildTypes().clear();
            node.setChildTypes(null);
        }
    }
    
    public JSONObject toViewJSON() {
        JSONObject tree = new JSONObject();
        
        tree.accumulate(JSON_ATTRIBUTE_TYPE_NAME, "Все");
        tree.accumulate(JSON_ATTRIBUTE_TYPE_ID, "0");
        
        JSONArray subtypes = new JSONArray();
        if (mainTypes != null && mainTypes.size() > 0) {
            for(int i=0;i<mainTypes.size();i++) {
                subtypes.add(nodeToViewJSON(mainTypes.get(i)));
            }
        }
        
        tree.accumulate(JSON_ATTRIBUTE_SUBTYPES, subtypes);
        
        return tree;
    }
    
    private JSONObject nodeToViewJSON(ComponentTypeEntity node) {
        JSONObject result = new JSONObject();
        
        JSONArray subtypes = new JSONArray();
        
        result.accumulate(JSON_ATTRIBUTE_TYPE_ID, node.getId());
        result.accumulate(JSON_ATTRIBUTE_TYPE_NAME, node.getName());
        
        if (node.getChildTypes() != null) {
            List<ComponentTypeEntity> children = node.getChildTypes();
            for(int i=0;i<children.size();i++) {
                subtypes.add(nodeToViewJSON(children.get(i)));
            }
        }
        
        result.accumulate(JSON_ATTRIBUTE_SUBTYPES, subtypes);
        
        return result;
    }
    
    /*public String toHTML() {
        String html = "<ul class=\"treeview\" data-role=\"treeview\">\n";
        
        if (mainTypes != null && mainTypes.size() > 0)
        {
            html += "<li class=\"node  collapsed\">\n" +
                "<a id=\"0\" href=\"#\"><span class=\"node-toggle\"></span>" +
                "Все" + "</a>\n<ul>\n";
            
            for(int i=0;i<mainTypes.size();i++) {
                html += nodeToHTML(mainTypes.get(i));
            }
            
            html += "</ul>\n</li>\n";
        }
        
        html += "</ul>";
        return html;
    }
    
    private String nodeToHTML(ComponentTypeEntity node) {
        String html;
        
        if (node.getChildTypes() != null) {
            html = "<li class=\"node collapsed\">\n" + 
                    "<a id=\"" + node.getId() + "\" href=\"#\"><span class=\"node-toggle\"></span>" +
                    node.getName() + "</a>\n<ul>\n";
            
            List<ComponentTypeEntity> children = node.getChildTypes();
            for(int i=0;i<children.size();i++) {
                html += nodeToHTML(children.get(i));
            }
            
            html += "</ul>\n</li>\n";
        } else {
            html = "<li><a id=\"" + node.getId() + "\" href=\"#\">" + node.getName() + "</a></li>\n";
        }
        
        return html;
    }*/
    
    public List<Long> getBranchIndexes(Long mainIndex) {
        return getChildIndexes(navigationTree.get(mainIndex));
    }

    private List<Long> getChildIndexes(ComponentTypeEntity get) {
        ArrayList<Long> result = new ArrayList<Long>();
        result.add(get.getId());
        if (get.getChildTypes() != null) {
            for(ComponentTypeEntity child : get.getChildTypes()) {
                    result.addAll(getChildIndexes(child));
            }
        }
        return result;
    }
    
    public JSONObject toOptionTreeJSON() {
        JSONObject json = new JSONObject();
        if (mainTypes != null && mainTypes.size() > 0)
        {
            for(int i=0;i<mainTypes.size();i++) {
                json.accumulate(mainTypes.get(i).getName(), nodeToOptionTreeJSON(mainTypes.get(i)));
            }
        }
        return json;
    }
    
    private JSONObject nodeToOptionTreeJSON(ComponentTypeEntity node) {
        JSONObject json = new JSONObject();
        json.accumulate("Не уточнять", node.getId());
 
        if (node.getChildTypes() != null) {
            List<ComponentTypeEntity> children = node.getChildTypes();
            for(int i=0;i<children.size();i++) {
                json.accumulate(children.get(i).getName(), nodeToOptionTreeJSON(children.get(i)));
            }
        }
        return json;
    }
}
